package com.idudiao.sc.common.core.handler;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.idudiao.sc.common.core.exception.base.BusinessException;
import com.idudiao.sc.common.core.constant.CommonConstants;
import com.idudiao.sc.common.core.exception.BaseException;
import com.idudiao.sc.common.core.msg.BaseResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * 全局异常拦截处理器
 *
 * @author songyinyin
 * @date 2018/12/14
 */
@ControllerAdvice("com.dhcc.aml")
@ResponseBody
public class GlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(BaseException.class)
    public BaseResponse baseExceptionHandler(HttpServletResponse response, BaseException ex) {
        logger.error(ex.getMessage(), ex);
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        return new BaseResponse(ex.getStatus(), ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public BaseResponse otherExceptionHandler(HttpServletResponse response, Exception ex) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        logger.error(ex.getMessage(), ex);
        return new BaseResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), ExceptionUtil.stacktraceToString(ex, 10000));
    }

    /**
     * 业务异常
     *
     * @param response
     * @param ex
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public BaseResponse businessExceptionHandler(HttpServletResponse response, BusinessException ex) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        logger.error(ex.getMessage(), ex);
        return new BaseResponse(ex.getStatus(), ex.getMessage());
    }

    /**
     * 使用注解 {@link javax.validation.Valid}和 {@link org.springframework.validation.annotation.Validated}
     * <p>验证不通过时抛出</p>
     * @param response
     * @param ex
     * @return
     */
    @ExceptionHandler(BindException.class)
    public BaseResponse bindExceptionHandler(HttpServletResponse response, BindException ex) {
        response.setStatus(HttpStatus.BAD_REQUEST.value());
        List<ObjectError> errors = ex.getAllErrors();
        logger.error(ex.getMessage(), ex);
        StringBuffer errorMsg = new StringBuffer();
        errors.stream().forEach(x ->
                errorMsg.append(x.getDefaultMessage()).append("\n")
        );
        return new BaseResponse(HttpStatus.BAD_REQUEST.value(), errorMsg.toString());
    }

    /**
     * 使用注解 {@link javax.validation.Valid}和 {@link org.springframework.validation.annotation.Validated}
     * <b>进行嵌套验证</b>被嵌套的属性验证不通过时会抛出 {@link MethodArgumentNotValidException}
     *
     * @param response
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public BaseResponse methodArgumentNotValidExceptionHandler(HttpServletResponse response, MethodArgumentNotValidException ex) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        logger.error(ex.getMessage(), ex);

        BindingResult result = ex.getBindingResult();
        final List<FieldError> fieldErrors = result.getFieldErrors();
        StringBuilder builder = new StringBuilder();
        for (FieldError error : fieldErrors) {
            builder.append(error.getDefaultMessage() + "\n");
        }
        return new BaseResponse(CommonConstants.EX_BUSINESS_BASE_CODE, builder.toString());
    }

    /**
     * 非法参数异常
     *
     * @param response
     * @param ex
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public BaseResponse illegalArgumentExceptionHandler(HttpServletResponse response, IllegalArgumentException ex) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        logger.error(ex.getMessage(), ex);
        return new BaseResponse(CommonConstants.EX_BUSINESS_BASE_CODE, ex.getMessage());
    }

}
